package com.food.eat.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

/**
 * @Author:RenPu
 * @Date: 2020/7/20 15:07
 * @Version: 1.0
 * @description: 编写用于观察service执行过程，所消耗的时间aop类   便于针对定位某个方法耗时过长，便于定位进行优化
 */

@Aspect
@Component
public class ServiceLogAspect {


    public static final Logger logger = LoggerFactory.getLogger(ServiceLogAspect.class);

    /**
     * aop:五种模式
     * 前置通知：在方法调用之前进行执行
     * 后置通知：在方法调用后进行执行
     * 环绕通知：在方法调用之前或者之后，都分别可以执行的通知
     * 异常通知：如果在方法调用时，出现异常则进行通知
     * 最终通知：在方法调用之后进行执行（类似final）
     */

    /**
     * 切面类表达式：
     * execution:要执行的表达式主体
     * 第一处 * 代表返回值类型，* 代表所有类型
     * 第二处 包名 aop监控包下所有的类
     * 第三处 .. 代表该包以及其子包，下的所有的类和方法
     * 第四处 * 代表类名，* 代表所有类
     * 第五处 *(..)  *代表方法名称，（..）代表方法的参数
     *
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    @Around("execution(* com.food.eat.impl..*.*(..))")
    public Object recordTimeLog(ProceedingJoinPoint joinPoint) throws Throwable {
        logger.info("=========开始执行 {}.{} ===========",
                joinPoint.getTarget().getClass(),              //获取执行的类名
                joinPoint.getSignature().getName());           //获取执行类里具体的方法


        //获取执行的起始时间
        long begin = System.currentTimeMillis();

        //Thread.sleep( 5000 );   //模拟测试功能

        //执行目标service
        Object result = joinPoint.proceed();

        //获取执行的终止时间
        long end = System.currentTimeMillis();

        //获取消耗时间
        long takeTime = end - begin;

        if (takeTime > 3000) {
            logger.error("===== 执行结束，耗时：{} 毫秒 =====", takeTime);
        } else if (takeTime > 2000) {
            logger.warn("===== 执行结束，耗时：{} 毫秒 =====", takeTime);

        } else if (takeTime > 1000) {
            logger.info("===== 执行结束，耗时：{} 毫秒 =====", takeTime);
        }

        return result;

    }


}
